import { _decorator, animation,  AnimationClip, math, PhysicsSystem2D, RigidBody2D, Sprite, SpriteFrame, Vec2 } from 'cc';
import { ANIMATION_SPEED, IState } from '../../Base/State';
import { ENTITY_STATE_ENUM } from '../../Enum';
import { ResourceManager } from '../../Runtime/ResourceManager';
import { sortSpriteFrame } from '../../Utils';
import { PlayerStateMachine } from './PlayerStateMachine';
import { InputManager } from '../../Base/InputManager';
import { PlayerDataWithDash } from '../PlayerDataWithDash';
const { ccclass, property } = _decorator;

@ccclass('playerState')
export class playerState implements IState<ENTITY_STATE_ENUM> {

    animationClip: AnimationClip
    id: ENTITY_STATE_ENUM;
    anim: string;
    rb: RigidBody2D | null = null;
    triggerCalled: boolean = false;
    stateTime: number = 0;
    data: PlayerDataWithDash;
    

    constructor(
        name: ENTITY_STATE_ENUM,
        anim: ENTITY_STATE_ENUM,
        public fsm: PlayerStateMachine,
        private spriteFrameDir: string,
        private wrapMode: AnimationClip.WrapMode = AnimationClip.WrapMode.Normal,
        private speed: number = ANIMATION_SPEED,
        private events: Array<AnimationClip.IEvent> = [],
    ) {
        this.id = name;
        this.anim = anim;
        this.rb = this.fsm.player.rb;
        this.data = this.fsm.player.data;

        this.init()
    }

    async init() {
        //生成动画轨道属性
        const track = new animation.ObjectTrack()
        track.path = new animation.TrackPath().toComponent(Sprite).toProperty('spriteFrame')
        const waiting = ResourceManager.Instance.loadDir(this.spriteFrameDir, SpriteFrame)
        this.fsm.waitingList.push(waiting)
        const spriteFrames = await waiting
        //去除最后一张总图
        spriteFrames.pop()

        const frames: Array<[number, SpriteFrame]> = sortSpriteFrame(spriteFrames).map((item, index) => [
            index * this.speed,
            item,
        ])
        track.channel.curve.assignSorted(frames)

        //动画添加轨道
        this.animationClip = new AnimationClip()
        this.animationClip.name = this.spriteFrameDir
        this.animationClip.duration = frames.length * this.speed
        this.animationClip.addTrack(track)
        this.animationClip.wrapMode = this.wrapMode
        for (const event of this.events) {
            this.animationClip.events.push(event)
        }
        this.animationClip.updateEventDatas()

        this.fsm.animationComponent.addClip(this.animationClip, this.anim)
    }

    onEnter() {
        // console.log('状态 => ', this.id)
        this.triggerCalled = false;
        this.fsm.animationComponent.play(this.anim);
        if (this.IsCoroutine()) {
            this.fsm.coroutine.replace(this.Coroutine())
            return;
        }
        this.fsm.coroutine.cancel();
    }
    onExit() {
        // this.player.BusyFor(20);
        // console.log('离开 => ', this.id)
    }
    update(deltaTime: number) { 

        this.stateTime += deltaTime; 

        this.checkCollisions();

        if (InputManager.Instance.moveDir.x !== 0) {
            if (this.id === ENTITY_STATE_ENUM.SLIDE) {
                this.checkDirectionToFace(InputManager.Instance.moveDir.x < 0);
                return;
            }
            this.checkDirectionToFace(InputManager.Instance.moveDir.x > 0);
        }
        
        if(this.canDash() && this.fsm.lastPressedDashTime > 0 ){
            this.fsm.transit(ENTITY_STATE_ENUM.DASH)
        }
    }
    canDash() :boolean {
        if (this.id != ENTITY_STATE_ENUM.DASH && this.fsm.dashAmount < this.fsm.player.data.dashAmount && this.fsm.lastOnGroundTime > 0 && !this.fsm.dashRefilling) {
            this.refillDash(1);
        }
        return this.fsm.dashAmount > 0;
    }
    private refillDash(amount: number) {
        this.fsm.dashRefilling = true;
        setTimeout(() => {
            this.fsm.dashRefilling = false;
            this.fsm.dashAmount = Math.min(this.fsm.player.data.dashAmount, this.fsm.dashAmount + amount);
        }, this.fsm.player.data.dashRefillTime * 1000);
    }

    onDestroy() { }
    *Coroutine(): Generator {
        console.log('Coroutine');
    }
    IsCoroutine():boolean{
        return false;
    }
    canTransit(to: ENTITY_STATE_ENUM): boolean { 
        if(to === this.id) return false;
        return true; 
    }
    AnimationFinishTrigger(): void { this.triggerCalled = true; }

    public checkDirectionToFace(isMovingRight: boolean) {
        if (isMovingRight !== this.fsm.isFacingRight) {
            this.turn();
        }
    }
    private turn() {
        this.fsm.node.scale.multiply3f(-1, 1, 1);
        this.fsm.isFacingRight = !this.fsm.isFacingRight;
    }

    private checkCollisions() {
        if(this.rb.linearVelocity.y > 0) return;

        const player = this.fsm.player;
        if (player.groundCheck && (player.groundCheck.contacts.length > 0)) {
            this.fsm.lastOnGroundTime = player.data.coyoteTime;
        }

        const rightWall = player.rightWallCheck && player.rightWallCheck.contacts.length > 0;
        const leftWall = player.leftWallCheck && player.leftWallCheck.contacts.length > 0;

        if (rightWall) {
            this.fsm.lastOnWallRightTime = player.data.coyoteTime;
        }

        if (leftWall) {
            this.fsm.lastOnWallLeftTime = player.data.coyoteTime;
        }

        this.fsm.lastOnWallTime = Math.max(this.fsm.lastOnWallLeftTime, this.fsm.lastOnWallRightTime);
    }

    run(lerpAmount: number) {
        // console.log("run");
        const move = InputManager.Instance.moveDir;
        const data = this.fsm.player.data;
        //目标速度
        let targetSpeed = move.x * data.runMaxSpeed;
        targetSpeed = math.lerp(this.rb.linearVelocity.x, targetSpeed, lerpAmount)
        //是否在地面
        let accelRate: number;
        if (this.fsm.lastOnGroundTime > 0) {
            accelRate = (Math.abs(targetSpeed) > 0.01) ? data.runAccelAmount : data.runDeccelAmount;
        } else {
            accelRate = (Math.abs(targetSpeed) > 0.01) ?
                data.runAccelAmount * data.accelInAir :
                data.runDeccelAmount * data.deccelInAir;
        }
        //悬停优化
        if (this.id === (ENTITY_STATE_ENUM.JUMP || ENTITY_STATE_ENUM.WALL_JUMP|| ENTITY_STATE_ENUM.FALL) &&
            Math.abs(this.rb.linearVelocity.y) < data.jumpHangTimeThreshold) {
            accelRate *= data.jumpHangAccelerationMult;
            targetSpeed *= data.jumpHangMaxSpeedMult;
        }
        //保持动量
        if (data.doConserveMomentum &&
            Math.abs(this.rb.linearVelocity.x) > Math.abs(targetSpeed) &&
            Math.sign(this.rb.linearVelocity.x) === Math.sign(targetSpeed) &&
            Math.abs(targetSpeed) > 0.01 &&
            this.fsm.lastOnGroundTime < 0) {
            accelRate = 0;// 禁用加速度
        }
        //最终力的计算
        // const speedDif = targetSpeed - this.rb.linearVelocity.x;
        // const movement = speedDif * accelRate * PhysicsSystem2D.instance.fixedTimeStep;
        // this.rb.applyForceToCenter(new Vec2(movement, 0), true);

        const speedDif = targetSpeed - this.rb.linearVelocity.x;
        const acceleration = speedDif * accelRate;
        const force = acceleration * this.rb.getMass(); // 力 = 质量 × 加速度
        this.rb.applyForceToCenter(new Vec2(force, 0), true);
        // console.log("applyForceToCenter -->",this.rb.linearVelocity);
    }
}

